/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.ainlolcat.ainscience.matrix;

import org.ainlolcat.ainscience.utils.PathUtils;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 *
 * @author ain
 */
public class MatrixFileParser {
    /*
     * count of string which will be omitted in parsing and addet to caption
     * by default no caption
     */
    private Integer captionStringCount = -1;
    private Integer captionStringNum = -1;

    /*
     * split matrix if valie of some type with some value occures in some column some times
     * by default ni split
     */
    private Boolean multipleFile = false;
    private Integer matrixDelimeterColumn = -1;
    private Object matrixDelimeterValue = null;
    private Integer matrixDelimeterValueType = -1;
    private Integer matrixDelimeterValueRep = -1;
    public static Integer MATRIX_DELIMETER_TYPE_INTEGER = 0;
    public static Integer MATRIX_DELIMETER_TYPE_DOUBLE = 1;
    public static Integer MATRIX_DELIMETER_TYPE_STRING = 2;
    public static Integer MATRIX_DELIMETER_TYPE_BOOLEAN = 3;

    private String lineDelimeterSymbols;

    public MatrixFileParser(){
        //add default line delimeter
        lineDelimeterSymbols = "";
    }

    public MatrixFile parseFile(Hashtable properties, String filename) throws IOException{
        FileInputStream fis = null;
        try{
            String realFilename = PathUtils.replaceMacros(filename);
            fis = new FileInputStream(realFilename);
            return parseStream(properties,fis);
        }catch(IOException e){
            e.printStackTrace();
            throw e;
        }finally{
            fis.close();
        }
    }
    
    public MatrixFile parseStream(Hashtable properties, InputStream file) throws IOException{
        parseParams(properties);

        BufferedReader br = new BufferedReader(new InputStreamReader(file));

        MatrixFile out = new MatrixFile();
        Matrix current = new Matrix();
        int rowCount = 0;
        boolean needCaption = (captionStringCount>0);
        int matrixDelimeterOccurenceCount = 0;
        while (br.ready()){            
            String line = br.readLine();
            //AinCalc for caption/trash at begin
            if (needCaption&&captionStringCount>0){
                if (rowCount==captionStringNum){
                    StringTokenizer st = new StringTokenizer(line, lineDelimeterSymbols);
                    int column = 0;
                    while (st.hasMoreElements()){
                        String token = st.nextToken();
                        current.setCaption(column, token);
                        column++;
                    }
                }
                if (rowCount<captionStringCount){
                    rowCount++;
                    continue;
                }
                else{
                    needCaption = false;
                }
            }
            //parse current line
            StringTokenizer st = new StringTokenizer(line, lineDelimeterSymbols);
            int column = 0;
            while (st.hasMoreElements()){
                String token = st.nextToken();
                //AinCalc for multiple file
                if (multipleFile&&column==matrixDelimeterColumn.intValue()){
                    //try to compare
                    try{
                        if (matrixDelimeterValueType==MATRIX_DELIMETER_TYPE_INTEGER.intValue()){
                            Integer cur = Integer.parseInt(token);
                            if (cur.equals(matrixDelimeterValue)){
                                matrixDelimeterOccurenceCount++;
                            }
                        }
                        if (matrixDelimeterValueType==MATRIX_DELIMETER_TYPE_DOUBLE.intValue()){
                            Double cur = Double.parseDouble(token);
                            if (cur.equals(matrixDelimeterValue)){
                                matrixDelimeterOccurenceCount++;
                            }
                        }
                        if (matrixDelimeterValueType==MATRIX_DELIMETER_TYPE_STRING.intValue()){
                            if (token.equals(matrixDelimeterValue)){
                                matrixDelimeterOccurenceCount++;
                            }
                        }
                    }catch(NumberFormatException e){
                        System.out.println("WARNING: wrong number format");
                        matrixDelimeterOccurenceCount = 0;
                    }
                    if (matrixDelimeterOccurenceCount>=matrixDelimeterValueRep){
                        for (int i=0;i<matrixDelimeterOccurenceCount;i++){
                            current.removeLastRow();
                        }
                        out.addMatrix(current);
                        Matrix old = current;
                        current = new Matrix();
                        if (captionStringCount>0){
                            Set<Integer> keys = old.getKeys();
                            for (Integer key:keys){
                                String name = old.getColumn(key).getName();
                                current.setCaption(key,name);
                            }
                        }
                        matrixDelimeterOccurenceCount=0;
                    }
                }
                current.addData(column, token);
                column++;
            }
            rowCount++;
        }
        out.addMatrix(current);
        return out;
    }

    private void parseParams(Hashtable properties){
        //see if you wanna omit some string in begining
        if (properties.get(Consts.CAPTION_STRING_COUNT)!=null){
            captionStringCount = (Integer) properties.get(Consts.CAPTION_STRING_COUNT);
            if (properties.get(Consts.CAPTION_STRING_NUM)!=null){
                captionStringNum = (Integer) properties.get(Consts.CAPTION_STRING_NUM);
            }
        }
        //see if you wanna parse file to two or more
        if (properties.get(Consts.MULTIPLE_FILE)!=null){
            multipleFile = (Boolean) properties.get(Consts.MULTIPLE_FILE);
            if (properties.get(Consts.MATRIX_DELIMETER_COLUMN)!=null){
                matrixDelimeterColumn = (Integer) properties.get(Consts.MATRIX_DELIMETER_COLUMN);
            }
            if (properties.get(Consts.MATRIX_DELIMETER_VALUE)!=null){
                matrixDelimeterValue = properties.get(Consts.MATRIX_DELIMETER_VALUE);
            }
            if (properties.get(Consts.MATRIX_DELIMETER_VALUE_TYPE)!=null){
                matrixDelimeterValueType = (Integer) properties.get(Consts.MATRIX_DELIMETER_VALUE_TYPE);
            }
            if (properties.get(Consts.MATRIX_DELIMETER_VALUE_REP)!=null){
                matrixDelimeterValueRep = (Integer) properties.get(Consts.MATRIX_DELIMETER_VALUE_REP);
            }
        } else multipleFile = false;
        //see for new delimeters
        if (properties.get(Consts.LINE_DELIMETER_SYMBOLS)!=null){
            lineDelimeterSymbols += (String) properties.get(Consts.LINE_DELIMETER_SYMBOLS);
        }
        if (properties.get(Consts.USE_SPACE_LINE_DELIMETER_SYMBOLS)!=null){
            if ((Boolean)properties.get(Consts.USE_SPACE_LINE_DELIMETER_SYMBOLS))
                lineDelimeterSymbols += " ";
        }
        if (properties.get(Consts.USE_TAB_LINE_DELIMETER_SYMBOLS)!=null){
            if ((Boolean)properties.get(Consts.USE_TAB_LINE_DELIMETER_SYMBOLS))
                lineDelimeterSymbols += "\t";
        }
    }

}
